const fetch = require('node-fetch');
const testLogger = require('../playwright-tests/utils/test-logger.js');

class APICleanup {
    constructor() {
        this.baseUrl = process.env.ZO_BASE_URL;
        this.org = process.env.ORGNAME;
        this.email = process.env.ZO_ROOT_USER_EMAIL;
        this.password = process.env.ZO_ROOT_USER_PASSWORD;
        this.authHeader = 'Basic ' + Buffer.from(`${this.email}:${this.password}`).toString('base64');
    }

    /**
     * Fetch all destinations and build template-destination mapping
     * @returns {Promise<Object>} Object with destinations array and templateToDestinations map
     */
    async fetchDestinationsWithTemplateMapping() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/alerts/destinations?page_num=1&page_size=100000&sort_by=name&desc=false&module=alert`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch destinations', { status: response.status });
                return { destinations: [], templateToDestinations: {} };
            }

            const destinations = await response.json();

            // Build map of template name -> destination names
            const templateToDestinations = {};
            for (const dest of destinations) {
                if (dest.template) {
                    if (!templateToDestinations[dest.template]) {
                        templateToDestinations[dest.template] = [];
                    }
                    templateToDestinations[dest.template].push(dest.name);
                }
            }

            return { destinations, templateToDestinations };
        } catch (error) {
            testLogger.error('Failed to fetch destinations', { error: error.message });
            return { destinations: [], templateToDestinations: {} };
        }
    }

    /**
     * Fetch all alert folders
     * @returns {Promise<Array>} Array of folder objects with folderId and name
     */
    async fetchAlertFolders() {
        try {
            const response = await fetch(`${this.baseUrl}/api/v2/${this.org}/folders/alerts`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch alert folders', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch alert folders', { error: error.message });
            return [];
        }
    }

    /**
     * Fetch alerts in a specific folder
     * @param {string} folderId - The folder ID
     * @returns {Promise<Array>} Array of alert objects
     */
    async fetchAlertsInFolder(folderId) {
        try {
            const response = await fetch(`${this.baseUrl}/api/v2/${this.org}/alerts?sort_by=name&desc=false&name=&folder=${folderId}`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch alerts in folder', { folderId, status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch alerts in folder', { folderId, error: error.message });
            return [];
        }
    }

    /**
     * Delete a single alert
     * @param {string} alertId - The alert ID
     * @param {string} folderId - The folder ID
     * @returns {Promise<Object>} Deletion result
     */
    async deleteAlert(alertId, folderId) {
        try {
            const response = await fetch(`${this.baseUrl}/api/v2/${this.org}/alerts/${alertId}?folder=${folderId}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete alert', { alertId, folderId, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Delete a folder
     * @param {string} folderId - The folder ID
     * @returns {Promise<Object>} Deletion result
     */
    async deleteFolder(folderId) {
        try {
            const response = await fetch(`${this.baseUrl}/api/v2/${this.org}/folders/alerts/${folderId}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            // API returns plain text "Folder deleted" instead of JSON
            const text = await response.text();

            // If successful, return standardized response
            if (response.ok) {
                return { code: 200, message: text };
            }

            // Try to parse as JSON for error responses
            try {
                const jsonResult = JSON.parse(text);
                return jsonResult;
            } catch {
                return { code: response.status, message: text };
            }
        } catch (error) {
            testLogger.error('Failed to delete folder', { folderId, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Fetch all dashboard folders
     * @returns {Promise<Array>} Array of folder objects
     */
    async fetchDashboardFolders() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/folders`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch dashboard folders', { status: response.status });
                return [];
            }

            const folders = await response.json();
            return folders || [];
        } catch (error) {
            testLogger.error('Failed to fetch dashboard folders', { error: error.message });
            return [];
        }
    }

    /**
     * Fetch all dashboards in a specific folder
     * @param {string} folderName - The folder name (e.g., 'default')
     * @returns {Promise<Array>} Array of dashboard objects
     */
    async fetchDashboardsInFolder(folderName = 'default') {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/dashboards?page_num=0&page_size=1000&sort_by=name&desc=false&name=&folder=${folderName}`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch dashboards', { folder: folderName, status: response.status });
                return [];
            }

            const data = await response.json();
            return data.dashboards || [];
        } catch (error) {
            testLogger.error('Failed to fetch dashboards', { folder: folderName, error: error.message });
            return [];
        }
    }

    /**
     * Delete a single dashboard
     * @param {string} dashboardId - The dashboard ID
     * @param {string} folderId - The folder ID
     * @returns {Promise<Object>} Deletion result
     */
    async deleteDashboard(dashboardId, folderId) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/dashboards/${dashboardId}?folder=${folderId}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete dashboard', { dashboardId, folderId, status: response.status });
                return { code: response.status, message: 'Failed to delete dashboard' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete dashboard', { dashboardId, folderId, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Fetch all reports
     * @returns {Promise<Array>} Array of report objects
     */
    async fetchReports() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/reports`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch reports', { status: response.status });
                return [];
            }

            const reports = await response.json();
            return reports || [];
        } catch (error) {
            testLogger.error('Failed to fetch reports', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single report
     * @param {string} reportName - The report name
     * @returns {Promise<Object>} Deletion result
     */
    async deleteReport(reportName) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/reports/${reportName}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete report', { reportName, status: response.status });
                return { code: response.status, message: 'Failed to delete report' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete report', { reportName, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Fetch all pipelines
     * @returns {Promise<Array>} Array of pipeline objects
     */
    async fetchPipelines() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/pipelines`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch pipelines', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch pipelines', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single pipeline
     * @param {string} pipelineId - The pipeline ID
     * @returns {Promise<Object>} Deletion result
     */
    async deletePipeline(pipelineId) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/pipelines/${pipelineId}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete pipeline', { pipelineId, status: response.status });
                return { code: response.status, message: 'Failed to delete pipeline' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete pipeline', { pipelineId, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Fetch all functions
     * @returns {Promise<Array>} Array of function objects
     */
    async fetchFunctions() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/functions?page_num=1&page_size=100000&sort_by=name&desc=false&name=`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch functions', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch functions', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single function
     * @param {string} functionName - The function name
     * @returns {Promise<Object>} Deletion result
     */
    async deleteFunction(functionName) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/functions/${functionName}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete function', { functionName, status: response.status });
                return { code: response.status, message: 'Failed to delete function' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete function', { functionName, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Fetch all enrichment tables
     * @returns {Promise<Array>} Array of enrichment table objects
     */
    async fetchEnrichmentTables() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/streams?type=enrichment_tables`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch enrichment tables', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch enrichment tables', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single enrichment table
     * @param {string} tableName - The enrichment table name
     * @returns {Promise<Object>} Deletion result
     */
    async deleteEnrichmentTable(tableName) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/streams/${tableName}?type=enrichment_tables&delete_all=true`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete enrichment table', { tableName, status: response.status });
                return { code: response.status, message: 'Failed to delete enrichment table' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete enrichment table', { tableName, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Clean up all enrichment tables matching pattern "protocols_" followed by UUID and "_csv"
     * Deletes tables like protocols_f916681d_b71b_4edd_a4c1_00a8bf34b86d_csv
     */
    async cleanupEnrichmentTables() {
        testLogger.info('Starting enrichment tables cleanup');

        try {
            // Fetch all enrichment tables
            const tables = await this.fetchEnrichmentTables();
            testLogger.info('Fetched enrichment tables', { total: tables.length });

            // Filter tables matching pattern: "protocols_" + UUID pattern + "_csv"
            const pattern = /^protocols_[a-f0-9]{8}_[a-f0-9]{4}_[a-f0-9]{4}_[a-f0-9]{4}_[a-f0-9]{12}_csv$/;
            const matchingTables = tables.filter(t => pattern.test(t.name));
            testLogger.info('Found enrichment tables matching cleanup pattern', { count: matchingTables.length });

            if (matchingTables.length === 0) {
                testLogger.info('No enrichment tables to clean up');
                return;
            }

            // Delete each table
            let deletedCount = 0;
            let failedCount = 0;

            for (const table of matchingTables) {
                const result = await this.deleteEnrichmentTable(table.name);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted enrichment table', { name: table.name });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete enrichment table', { name: table.name, result });
                }
            }

            testLogger.info('Enrichment tables cleanup completed', {
                total: matchingTables.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Enrichment tables cleanup failed', { error: error.message });
        }
    }

    /**
     * Clean up all functions matching pattern "Pipeline" followed by exactly 3 digits
     * Deletes functions like Pipeline936, Pipeline657, etc.
     * Does NOT delete Pipeline1234, test123, alpha123, etc.
     */
    async cleanupFunctions() {
        testLogger.info('Starting functions cleanup');

        try {
            // Fetch all functions
            const functions = await this.fetchFunctions();
            testLogger.info('Fetched functions', { total: functions.length });

            // Filter functions matching pattern: "Pipeline" followed by exactly 3 digits
            const pattern = /^Pipeline\d{3}$/;
            const matchingFunctions = functions.filter(f => pattern.test(f.name));
            testLogger.info('Found functions matching cleanup pattern', { count: matchingFunctions.length });

            if (matchingFunctions.length === 0) {
                testLogger.info('No functions to clean up');
                return;
            }

            // Delete each function
            let deletedCount = 0;
            let failedCount = 0;

            for (const func of matchingFunctions) {
                const result = await this.deleteFunction(func.name);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted function', { name: func.name });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete function', { name: func.name, result });
                }
            }

            testLogger.info('Functions cleanup completed', {
                total: matchingFunctions.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Functions cleanup failed', { error: error.message });
        }
    }

    /**
     * Clean up all pipelines for specific streams
     * Deletes pipelines where source.stream_name matches any of the target streams
     * @param {Array<string>} streamNames - Array of stream names to match (default: ['e2e_automate', 'e2e_automate1', 'e2e_automate2', 'e2e_automate3'])
     */
    async cleanupPipelines(streamNames = ['e2e_automate', 'e2e_automate1', 'e2e_automate2', 'e2e_automate3']) {
        testLogger.info('Starting pipeline cleanup', { streams: streamNames });

        try {
            // Fetch all pipelines
            const pipelines = await this.fetchPipelines();
            testLogger.info('Fetched pipelines', { total: pipelines.length });

            // Filter pipelines by source stream name
            const matchingPipelines = pipelines.filter(p =>
                p.source && streamNames.includes(p.source.stream_name)
            );
            testLogger.info('Found pipelines matching target streams', { count: matchingPipelines.length });

            if (matchingPipelines.length === 0) {
                testLogger.info('No pipelines to clean up');
                return;
            }

            // Delete each pipeline
            let deletedCount = 0;
            let failedCount = 0;

            for (const pipeline of matchingPipelines) {
                const result = await this.deletePipeline(pipeline.pipeline_id);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted pipeline', {
                        id: pipeline.pipeline_id,
                        name: pipeline.name,
                        stream: pipeline.source.stream_name
                    });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete pipeline', {
                        id: pipeline.pipeline_id,
                        name: pipeline.name,
                        stream: pipeline.source.stream_name,
                        result
                    });
                }
            }

            testLogger.info('Pipeline cleanup completed', {
                total: matchingPipelines.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Pipeline cleanup failed', { error: error.message });
        }
    }

    /**
     * Clean up all reports owned by the automation test user
     * Deletes all reports where owner matches ZO_ROOT_USER_EMAIL
     */
    async cleanupReports() {
        testLogger.info('Starting reports cleanup', { owner: this.email });

        try {
            // Fetch all reports
            const reports = await this.fetchReports();
            testLogger.info('Fetched reports', { total: reports.length });

            // Filter reports owned by automation user
            const ownedReports = reports.filter(r => r.owner === this.email);
            testLogger.info('Found reports owned by automation user', { count: ownedReports.length });

            if (ownedReports.length === 0) {
                testLogger.info('No reports to clean up');
                return;
            }

            // Delete each report
            let deletedCount = 0;
            let failedCount = 0;

            for (const report of ownedReports) {
                const result = await this.deleteReport(report.name);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted report', {
                        id: report.report_id,
                        name: report.name
                    });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete report', {
                        id: report.report_id,
                        name: report.name,
                        result
                    });
                }
            }

            testLogger.info('Reports cleanup completed', {
                total: ownedReports.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Reports cleanup failed', { error: error.message });
        }
    }

    /**
     * Clean up all dashboards owned by the automation test user
     * Deletes dashboards from the 'default' folder where owner matches ZO_ROOT_USER_EMAIL
     */
    async cleanupDashboards() {
        testLogger.info('Starting dashboard cleanup', { owner: this.email });

        try {
            // Fetch dashboards from default folder
            const dashboards = await this.fetchDashboardsInFolder('default');
            testLogger.info('Fetched dashboards', { total: dashboards.length });

            // Filter dashboards owned by automation user
            const ownedDashboards = dashboards.filter(d => d.owner === this.email);
            testLogger.info('Found dashboards owned by automation user', { count: ownedDashboards.length });

            if (ownedDashboards.length === 0) {
                testLogger.info('No dashboards to clean up');
                return;
            }

            // Delete each dashboard
            let deletedCount = 0;
            let failedCount = 0;

            for (const dashboard of ownedDashboards) {
                const result = await this.deleteDashboard(dashboard.dashboard_id, dashboard.folder_id);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted dashboard', {
                        id: dashboard.dashboard_id,
                        title: dashboard.title
                    });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete dashboard', {
                        id: dashboard.dashboard_id,
                        title: dashboard.title,
                        result
                    });
                }
            }

            testLogger.info('Dashboard cleanup completed', {
                total: ownedDashboards.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Dashboard cleanup failed', { error: error.message });
        }
    }

    /**
     * Fetch all log streams
     * @returns {Promise<Array>} Array of stream objects
     */
    async fetchStreams() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/streams?type=logs`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch streams', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.list || [];
        } catch (error) {
            testLogger.error('Failed to fetch streams', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single stream
     * @param {string} streamName - The stream name
     * @returns {Promise<Object>} Deletion result
     */
    async deleteStream(streamName) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/streams/${streamName}?type=logs&delete_all=true`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete stream', { streamName, status: response.status });
                return { code: response.status, message: 'Failed to delete stream' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete stream', { streamName, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Clean up all streams starting with "sanitylogstream_"
     * Deletes streams like sanitylogstream_61hj, sanitylogstream_abc123, etc.
     */
    /**
     * Check if a stream name should be cleaned up
     * Cleans up streams matching these patterns:
     * 1. Starts with "sanitylogstream_"
     * 2. Matches test patterns: test1, test2, test3, etc.
     * 3. stress_test followed by numbers
     * 4. Random 8-9 character lowercase strings (from pipeline dynamic tests)
     *    - BUT excludes known production/important streams
     */
    shouldCleanupStream(streamName) {
        // Pattern 1: sanitylogstream_*
        if (streamName.startsWith('sanitylogstream_')) {
            return true;
        }

        // Pattern 2: test1, test2, test3, etc.
        if (/^test\d+$/.test(streamName)) {
            return true;
        }

        // Pattern 3: stress_test*
        if (streamName.startsWith('stress_test')) {
            return true;
        }

        // Pattern 4: Random 8-9 char lowercase strings
        // First check if it matches the basic pattern
        if (!/^[a-z]{8,9}$/.test(streamName)) {
            return false;
        }

        // Whitelist of known important streams to never delete
        const protectedStreams = [
            'default', 'sensitive', 'important', 'critical',
            'production', 'staging', 'automation'
        ];

        // Don't delete if it's in the protected list
        if (protectedStreams.includes(streamName)) {
            return false;
        }

        // Don't delete if it contains common meaningful patterns
        const meaningfulPatterns = ['prod', 'test', 'auto', 'log', 'metric', 'trace'];
        if (meaningfulPatterns.some(pattern => streamName.includes(pattern))) {
            return false;
        }

        // If it's 8-9 random lowercase chars and not protected, delete it
        return true;
    }

    async cleanupStreams() {
        testLogger.info('Starting streams cleanup');

        try {
            // Fetch all log streams
            const streams = await this.fetchStreams();
            testLogger.info('Fetched streams', { total: streams.length });

            // Filter streams matching cleanup patterns
            const matchingStreams = streams.filter(s => this.shouldCleanupStream(s.name));
            testLogger.info('Found streams matching cleanup patterns', { count: matchingStreams.length });

            if (matchingStreams.length === 0) {
                testLogger.info('No streams to clean up');
                return;
            }

            // Delete each stream
            let deletedCount = 0;
            let failedCount = 0;

            for (const stream of matchingStreams) {
                const result = await this.deleteStream(stream.name);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted stream', { name: stream.name });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete stream', { name: stream.name, result });
                }
            }

            testLogger.info('Streams cleanup completed', {
                total: matchingStreams.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Streams cleanup failed', { error: error.message });
        }
    }

    /**
     * Fetch all service accounts
     * @returns {Promise<Array>} Array of service account objects
     */
    async fetchServiceAccounts() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/service_accounts`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch service accounts', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.data || [];
        } catch (error) {
            testLogger.error('Failed to fetch service accounts', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single service account
     * @param {string} email - The service account email
     * @returns {Promise<Object>} Deletion result
     */
    async deleteServiceAccount(email) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/service_accounts/${email}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete service account', { email, status: response.status });
                return { code: response.status, message: 'Failed to delete service account' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete service account', { email, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Clean up all service accounts matching pattern "email*@gmail.com"
     * Deletes service accounts with emails starting with "email" and ending with "@gmail.com"
     */
    async cleanupServiceAccounts() {
        testLogger.info('Starting service accounts cleanup');

        try {
            // Fetch all service accounts
            const serviceAccounts = await this.fetchServiceAccounts();
            testLogger.info('Fetched service accounts', { total: serviceAccounts.length });

            // Filter service accounts matching pattern: starts with "email" and ends with "@gmail.com"
            const pattern = /^email.*@gmail\.com$/;
            const matchingAccounts = serviceAccounts.filter(sa => pattern.test(sa.email));
            testLogger.info('Found service accounts matching cleanup pattern', { count: matchingAccounts.length });

            if (matchingAccounts.length === 0) {
                testLogger.info('No service accounts to clean up');
                return;
            }

            // Delete each service account
            let deletedCount = 0;
            let failedCount = 0;

            for (const account of matchingAccounts) {
                const result = await this.deleteServiceAccount(account.email);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted service account', { email: account.email });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete service account', { email: account.email, result });
                }
            }

            testLogger.info('Service accounts cleanup completed', {
                total: matchingAccounts.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Service accounts cleanup failed', { error: error.message });
        }
    }

    /**
     * Fetch all users
     * @returns {Promise<Array>} Array of user objects
     */
    async fetchUsers() {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/users`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to fetch users', { status: response.status });
                return [];
            }

            const data = await response.json();
            return data.data || [];
        } catch (error) {
            testLogger.error('Failed to fetch users', { error: error.message });
            return [];
        }
    }

    /**
     * Delete a single user
     * @param {string} email - The user email
     * @returns {Promise<Object>} Deletion result
     */
    async deleteUser(email) {
        try {
            const response = await fetch(`${this.baseUrl}/api/${this.org}/users/${email}`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete user', { email, status: response.status });
                return { code: response.status, message: 'Failed to delete user' };
            }

            const result = await response.json();
            return result;
        } catch (error) {
            testLogger.error('Failed to delete user', { email, error: error.message });
            return { code: 500, error: error.message };
        }
    }

    /**
     * Clean up all users matching patterns "email*@gmail.com" and "duplicate*@gmail.com"
     * Deletes users with emails starting with "email" or "duplicate" and ending with "@gmail.com"
     */
    async cleanupUsers() {
        testLogger.info('Starting users cleanup');

        try {
            // Fetch all users
            const users = await this.fetchUsers();
            testLogger.info('Fetched users', { total: users.length });

            // Filter users matching patterns: starts with "email" or "duplicate" and ends with "@gmail.com"
            const emailPattern = /^email.*@gmail\.com$/;
            const duplicatePattern = /^duplicate.*@gmail\.com$/;
            const matchingUsers = users.filter(user =>
                emailPattern.test(user.email) || duplicatePattern.test(user.email)
            );
            testLogger.info('Found users matching cleanup patterns', { count: matchingUsers.length });

            if (matchingUsers.length === 0) {
                testLogger.info('No users to clean up');
                return;
            }

            // Delete each user
            let deletedCount = 0;
            let failedCount = 0;

            for (const user of matchingUsers) {
                const result = await this.deleteUser(user.email);

                if (result.code === 200) {
                    deletedCount++;
                    testLogger.debug('Deleted user', { email: user.email });
                } else {
                    failedCount++;
                    testLogger.warn('Failed to delete user', { email: user.email, result });
                }
            }

            testLogger.info('Users cleanup completed', {
                total: matchingUsers.length,
                deleted: deletedCount,
                failed: failedCount
            });

        } catch (error) {
            testLogger.error('Users cleanup failed', { error: error.message });
        }
    }

    /**
     * Clean up custom logo from _meta organization
     * Deletes the custom logo via DELETE API call
     */
    async cleanupLogo() {
        testLogger.info('Starting logo cleanup');

        try {
            const response = await fetch(`${this.baseUrl}/api/_meta/settings/logo`, {
                method: 'DELETE',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) {
                testLogger.error('Failed to delete logo', { status: response.status });
                return { successful: 'false', status: response.status };
            }

            const result = await response.json();

            if (result.successful === 'true') {
                testLogger.info('Logo cleanup completed successfully');
            } else {
                testLogger.warn('Logo cleanup returned unexpected result', { result });
            }

            return result;
        } catch (error) {
            testLogger.error('Logo cleanup failed', { error: error.message });
            return { successful: 'false', error: error.message };
        }
    }

    /**
     * Complete cascade cleanup: Alert -> Folder -> Destination -> Template
     * Only deletes resources linked to destinations matching the prefix
     * @param {string} prefix - Prefix to match destination names (e.g., 'auto_playwright')
     */
    async completeCascadeCleanup(prefix = 'auto_playwright') {
        testLogger.info('Starting complete cascade cleanup', { prefix });

        try {
            // Step 1: Fetch all destinations and filter by prefix (including newdest_ and sanitydest-)
            const { destinations, templateToDestinations } = await this.fetchDestinationsWithTemplateMapping();
            const matchingDestinations = destinations.filter(d =>
                d.name.startsWith(prefix) ||
                d.name.startsWith('newdest_') ||
                d.name.startsWith('sanitydest-')
            );

            testLogger.info('Found destinations to process', { total: matchingDestinations.length });

            const failedDestinations = [];
            const deletedDestinations = [];
            const linkedTemplates = new Set();

            // Only process destinations if we found any matching the prefix
            if (matchingDestinations.length > 0) {
                // Step 2: Attempt to delete each destination
                for (const destination of matchingDestinations) {
                // Track template for potential cleanup
                if (destination.template) {
                    linkedTemplates.add(destination.template);
                }

                const deleteResult = await fetch(`${this.baseUrl}/api/${this.org}/alerts/destinations/${destination.name}`, {
                    method: 'DELETE',
                    headers: {
                        'Authorization': this.authHeader,
                        'Content-Type': 'application/json'
                    }
                });

                const result = await deleteResult.json();

                if (result.code === 409 && result.message) {
                    // Extract alert name from error
                    const match = result.message.match(/alert:\s*(.+)$/);
                    const linkedAlert = match && match[1] ? match[1].trim() : null;

                    if (linkedAlert) {
                        failedDestinations.push({
                            destinationName: destination.name,
                            templateName: destination.template,
                            alertName: linkedAlert
                        });
                        testLogger.info('Destination blocked by alert', {
                            destination: destination.name,
                            alert: linkedAlert,
                            template: destination.template
                        });
                    }
                } else if (result.code === 200) {
                    deletedDestinations.push(destination.name);
                    testLogger.debug('Deleted destination successfully', { name: destination.name });
                }
            }

            testLogger.info('Initial destination deletion summary', {
                total: matchingDestinations.length,
                deleted: deletedDestinations.length,
                blocked: failedDestinations.length
            });

            // Step 3: Fetch all folders (only if there are failed destinations)
            let folders = [];
            if (failedDestinations.length > 0) {
                folders = await this.fetchAlertFolders();
                testLogger.info('Fetched alert folders', { total: folders.length });
            }

            // Step 4: Process each failed destination with cascade
            for (const failed of failedDestinations) {
                testLogger.info('Processing cascade cleanup', {
                    destination: failed.destinationName,
                    alert: failed.alertName,
                    template: failed.templateName
                });

                // Extract suffix from alert name (e.g., Automation_Alert_8OvH5 -> 8OvH5)
                const alertSuffix = failed.alertName.split('_').pop();
                const expectedFolderName = `auto_${alertSuffix}`;

                // Try to find matching folder by name first
                let folder = folders.find(f => f.name === expectedFolderName);
                let alerts = [];

                if (!folder) {
                    testLogger.warn('Could not find expected folder, searching all folders for alert', {
                        alert: failed.alertName,
                        expectedFolder: expectedFolderName
                    });

                    // Search testfoldermove first, then all other folders
                    const testFolderMove = folders.find(f => f.name === 'testfoldermove');
                    const otherFolders = folders.filter(f => f.name !== 'testfoldermove');
                    const searchOrder = testFolderMove ? [testFolderMove, ...otherFolders] : folders;

                    // Search through each folder to find the alert
                    for (const searchFolder of searchOrder) {
                        const alertsInFolder = await this.fetchAlertsInFolder(searchFolder.folderId);
                        const foundAlert = alertsInFolder.find(a => a.name === failed.alertName);

                        if (foundAlert) {
                            folder = searchFolder;
                            alerts = alertsInFolder;
                            testLogger.info('Found alert in folder', {
                                alert: failed.alertName,
                                folderId: folder.folderId,
                                folderName: folder.name
                            });
                            break;
                        }
                    }

                    if (!folder) {
                        testLogger.error('Could not find alert in any folder', {
                            alert: failed.alertName,
                            searchedFolders: folders.length
                        });
                        continue;
                    }
                } else {
                    testLogger.info('Found folder for alert', {
                        folderId: folder.folderId,
                        folderName: folder.name
                    });

                    // Step 5: Fetch alerts in folder
                    alerts = await this.fetchAlertsInFolder(folder.folderId);
                }

                testLogger.info('Alerts in folder', { count: alerts.length });

                // Step 6: Delete all alerts in folder
                for (const alert of alerts) {
                    const alertDeleteResult = await this.deleteAlert(alert.alert_id, folder.folderId);
                    if (alertDeleteResult.code === 200) {
                        testLogger.debug('Deleted alert', { alertId: alert.alert_id, name: alert.name });
                    } else {
                        testLogger.warn('Failed to delete alert', {
                            alertId: alert.alert_id,
                            name: alert.name,
                            result: alertDeleteResult
                        });
                    }
                }

                // Step 7: Delete folder
                const folderDeleteResult = await this.deleteFolder(folder.folderId);
                if (folderDeleteResult.code === 200) {
                    testLogger.info('Deleted folder', { folderId: folder.folderId, name: folder.name });
                } else {
                    testLogger.warn('Failed to delete folder', { folderId: folder.folderId, result: folderDeleteResult });
                }

                // Step 8: Delete destination (retry after alert removal)
                const destDeleteResult = await fetch(`${this.baseUrl}/api/${this.org}/alerts/destinations/${failed.destinationName}`, {
                    method: 'DELETE',
                    headers: {
                        'Authorization': this.authHeader,
                        'Content-Type': 'application/json'
                    }
                });
                const destResult = await destDeleteResult.json();
                if (destResult.code === 200) {
                    testLogger.info('Deleted destination', { name: failed.destinationName });
                    deletedDestinations.push(failed.destinationName);
                } else {
                    testLogger.warn('Failed to delete destination', { name: failed.destinationName, result: destResult });
                }
            }

                // Step 9: Delete templates that were linked to deleted destinations
                testLogger.info('Cleaning up linked templates', { templates: Array.from(linkedTemplates) });

                for (const templateName of linkedTemplates) {
                    const templateDeleteResult = await fetch(`${this.baseUrl}/api/${this.org}/alerts/templates/${templateName}`, {
                        method: 'DELETE',
                        headers: {
                            'Authorization': this.authHeader,
                            'Content-Type': 'application/json'
                        }
                    });
                    const templateResult = await templateDeleteResult.json();
                    if (templateResult.code === 200) {
                        testLogger.info('Deleted template', { name: templateName });
                    } else {
                        testLogger.warn('Failed to delete template', {
                            name: templateName,
                            result: templateResult,
                            note: 'Template may still be in use by other destinations'
                        });
                    }
                }
            }

            // Step 9b: Delete all auto_email_template_*, auto_webhook_template_*, sanitytemp-*, and newtemp_* templates
            testLogger.info('Cleaning up auto_email, auto_webhook, sanitytemp, and newtemp templates');

            const allTemplatesResponse = await fetch(`${this.baseUrl}/api/${this.org}/alerts/templates?page_num=1&page_size=100000&sort_by=name&desc=false`, {
                method: 'GET',
                headers: {
                    'Authorization': this.authHeader,
                    'Content-Type': 'application/json'
                }
            });

            if (allTemplatesResponse.ok) {
                const allTemplates = await allTemplatesResponse.json();
                const autoTemplates = allTemplates.filter(t =>
                    t.name.startsWith('auto_email_template_') ||
                    t.name.startsWith('auto_webhook_template_') ||
                    t.name.startsWith('sanitytemp-') ||
                    t.name.startsWith('newtemp_')
                );

                testLogger.info('Found templates to delete', { count: autoTemplates.length });

                for (const template of autoTemplates) {
                    const templateDeleteResult = await fetch(`${this.baseUrl}/api/${this.org}/alerts/templates/${template.name}`, {
                        method: 'DELETE',
                        headers: {
                            'Authorization': this.authHeader,
                            'Content-Type': 'application/json'
                        }
                    });
                    const templateResult = await templateDeleteResult.json();
                    if (templateResult.code === 200) {
                        testLogger.info('Deleted auto template', { name: template.name });
                    } else {
                        testLogger.warn('Failed to delete auto template', {
                            name: template.name,
                            result: templateResult
                        });
                    }
                }
            }

            // Step 10: Delete all remaining folders starting with 'auto_'
            testLogger.info('Cleaning up remaining folders starting with auto_');

            // Fetch fresh list of all folders
            const allFolders = await this.fetchAlertFolders();
            const autoFolders = allFolders.filter(f => f.name.startsWith('auto_'));
            testLogger.info('Found folders to clean up', { total: autoFolders.length });

            for (const folder of autoFolders) {
                // First, delete all alerts in the folder
                const alerts = await this.fetchAlertsInFolder(folder.folderId);

                if (alerts.length > 0) {
                    testLogger.info('Deleting alerts in folder before folder deletion', {
                        folderId: folder.folderId,
                        folderName: folder.name,
                        alertCount: alerts.length
                    });

                    for (const alert of alerts) {
                        const alertDeleteResult = await this.deleteAlert(alert.alert_id, folder.folderId);
                        if (alertDeleteResult.code === 200) {
                            testLogger.debug('Deleted alert', { alertId: alert.alert_id, name: alert.name });
                        } else {
                            testLogger.warn('Failed to delete alert', {
                                alertId: alert.alert_id,
                                name: alert.name,
                                result: alertDeleteResult
                            });
                        }
                    }
                }

                // Then delete the folder
                const folderDeleteResult = await this.deleteFolder(folder.folderId);

                // Handle both JSON and plain text responses
                if (folderDeleteResult.code === 200 || folderDeleteResult.message?.includes('Folder deleted')) {
                    testLogger.info('Deleted folder', { folderId: folder.folderId, name: folder.name });
                } else {
                    testLogger.warn('Failed to delete folder', {
                        folderId: folder.folderId,
                        name: folder.name,
                        result: folderDeleteResult
                    });
                }
            }

            testLogger.info('Complete cascade cleanup finished', {
                totalDestinations: matchingDestinations.length,
                deletedDestinations: deletedDestinations.length,
                linkedTemplates: linkedTemplates.size,
                foldersDeleted: autoFolders.length
            });

        } catch (error) {
            testLogger.error('Complete cascade cleanup failed', { error: error.message });
        }
    }
}

module.exports = APICleanup;
